// Copyright (c) 2005  INRIA Sophia-Antipolis (France).
// All rights reserved.
//
// This file is part of cgal-python; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; version 2.1 of the License.
// See the file LICENSE.LGPL distributed with cgal-python.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $Id: Py_Alpha_shape_3.cpp 167 2007-11-02 15:36:54Z spion $
// $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal-python/trunk/cgal-python/bindings/Alpha_shapes_3/Py_Alpha_shape_3.cpp $
// $Date: 2007-11-02 16:36:54 +0100 (Ven 02 nov 2007) $
// Author(s)     : Naceur Meskini
//=========================================================================

// Includes ====================================================================
#include <CGAL/basic.h>
#include <include/Kernels.h>
#include <CGAL/Triangulation_vertex_base_with_info_3.h>
#include <CGAL/Alpha_shape_vertex_base_3.h>
#include <CGAL/Delaunay_triangulation_3.h>
#include <CGAL/Alpha_shape_cell_base_3.h>
#include <CGAL/Alpha_shape_3.h>

// Boost Includes ==============================================================
#include <boost/python.hpp>
#include <boost/cstdint.hpp>
#include <include/iterator.h>
#include "Py_Alpha_shape_3_doc.h"

// Using =======================================================================
using namespace boost::python;

// Declarations ================================================================
namespace  {

BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(set_mode_overloads_0_1, set_mode, 0, 1)

}// namespace 
//===================================
template <class Alpha_shape_3,class class_name>
boost::python::list py_get_alpha_shape_cells(const Alpha_shape_3& as,typename Alpha_shape_3::Classification_type type)
{
	std::list<class_name> liste;
	boost::python::list result;

	as.get_alpha_shape_cells(std::back_inserter(liste),type);

	typename std::list<class_name>::iterator iter;
	for(iter = liste.begin() ; iter != liste.end() ; ++iter) result.append(*iter);
	return result;

}

template <class Alpha_shape_3,class class_name>
boost::python::list py_get_alpha_shape_cells_alpha(const Alpha_shape_3& as,typename Alpha_shape_3::Classification_type type,const double& alpha)
{
	std::list<class_name> liste;
	boost::python::list result;

	as.get_alpha_shape_cells(std::back_inserter(liste),type,alpha);

	typename std::list<class_name>::iterator iter;
	for(iter = liste.begin() ; iter != liste.end() ; ++iter) result.append(*iter);
	return result;

}
//==========================================
template <class Alpha_shape_3,class class_name>
boost::python::list py_get_alpha_shape_vertices(const Alpha_shape_3& as,typename Alpha_shape_3::Classification_type type)
{
	std::list<class_name> liste;
	boost::python::list result;

	as.get_alpha_shape_vertices(std::back_inserter(liste),type);

	typename std::list<class_name>::iterator iter;
	for(iter = liste.begin() ; iter != liste.end() ; ++iter) result.append(*iter);
	return result;

}

template <class Alpha_shape_3,class class_name>
boost::python::list py_get_alpha_shape_vertices_alpha(const Alpha_shape_3& as,typename Alpha_shape_3::Classification_type type,const double& alpha)
{
	std::list<class_name> liste;
	boost::python::list result;

	as.get_alpha_shape_vertices(std::back_inserter(liste),type,alpha);

	typename std::list<class_name>::iterator iter;
	for(iter = liste.begin() ; iter != liste.end() ; ++iter) result.append(*iter);
	return result;

}
//==========================================
template <class Alpha_shape_3,class class_name>
boost::python::list py_get_alpha_shape_edges(const Alpha_shape_3& as,typename Alpha_shape_3::Classification_type type)
{
	std::list<class_name> liste;
	boost::python::list result;

	as.get_alpha_shape_edges(std::back_inserter(liste),type);

	typename std::list<class_name>::iterator iter;
	for(iter = liste.begin() ; iter != liste.end() ; ++iter) result.append(*iter);
	return result;

}

template <class Alpha_shape_3,class class_name>
boost::python::list py_get_alpha_shape_edges_alpha(const Alpha_shape_3& as,typename Alpha_shape_3::Classification_type type,const double& alpha)
{
	std::list<class_name> liste;
	boost::python::list result;

	as.get_alpha_shape_edges(std::back_inserter(liste),type,alpha);

	typename std::list<class_name>::iterator iter;
	for(iter = liste.begin() ; iter != liste.end() ; ++iter) result.append(*iter);
	return result;

}
//===================================

template <class Alpha_shape_3,class class_name>
boost::python::list py_get_alpha_shape_facets(const Alpha_shape_3& as,typename Alpha_shape_3::Classification_type type)
{
	std::list<class_name> liste;
	boost::python::list result;

	as.get_alpha_shape_facets(std::back_inserter(liste),type);

	typename std::list<class_name>::iterator iter;
	for(iter = liste.begin() ; iter != liste.end() ; ++iter) result.append(*iter);
	return result;

}

template <class Alpha_shape_3,class class_name>
boost::python::list py_get_alpha_shape_facets_alpha(const Alpha_shape_3& as,typename Alpha_shape_3::Classification_type type,const double& alpha)
{
	std::list<class_name> liste;
	boost::python::list result;

	as.get_alpha_shape_facets(std::back_inserter(liste),type,alpha);

	typename std::list<class_name>::iterator iter;
	for(iter = liste.begin() ; iter != liste.end() ; ++iter) result.append(*iter);
	return result;

}

//==============
template < class iterator,class Alpha_shape_3>
simple_python_iterator<iterator> py_alpha(const Alpha_shape_3& as)
{
	std::pair< iterator , iterator > p( as.alpha_begin(), as.alpha_end() );
	return simple_python_iterator<iterator>(p);
}
//==================
template <class kernel,class iterator,class Alpha_shape_3>
simple_python_iterator<iterator> py_alpha_lower_bound(const Alpha_shape_3& as,const double& alpha)
{
	std::pair< iterator , iterator > p( as.alpha_lower_bound(alpha), as.alpha_end() );
	return simple_python_iterator<iterator>(p);
}
//==================
template <class kernel,class iterator,class Alpha_shape_3>
simple_python_iterator<iterator> py_alpha_upper_bound(const Alpha_shape_3& as,const double& alpha)
{
	std::pair< iterator , iterator > p( as.alpha_upper_bound(alpha), as.alpha_end() );
	return simple_python_iterator<iterator>(p);
}
//=================
//==================
template <class kernel,class iterator,class Alpha_shape_3>
simple_python_iterator<iterator> py_alpha_find(const Alpha_shape_3& as,const double& alpha)
{
	std::pair< iterator , iterator > p( as.alpha_find(alpha), as.alpha_end() );
	return simple_python_iterator<iterator>(p);
}
//=================
//==================
template <class iterator,class Alpha_shape_3>
simple_python_iterator<iterator> py_find_optimal_alpha(const Alpha_shape_3& as,int nb_components)
{
	std::pair< iterator , iterator > p( as.find_optimal_alpha(nb_components), as.alpha_end() );
	return simple_python_iterator<iterator>(p);
}

//==================
template <class kernel,class Alpha_shape_3>
int py_make_alpha_shape(Alpha_shape_3& as,const boost::python::list& points)
{
	typedef CGAL::Point_3<kernel> Point_3;
	std::list<Point_3> pts;
	int Nb = boost::python::extract<int>(points.attr("__len__")());
	for (int i = 0; i < Nb ; i++) pts.push_back(boost::python::extract<Point_3>(points[i]));
	return as.make_alpha_shape(pts.begin(),pts.end());
}
//==================

template <class Alpha_shape_3>
void py_set_alpha(Alpha_shape_3& as,const double& alpha)
{
	as.set_alpha(alpha);
}

template <class Alpha_shape_3>
int py_number_of_solid_components(const Alpha_shape_3& as,const double& alpha)
{
	return as.number_of_solid_components(alpha);
}

//==================
template <class Alpha_shape_3 ,class class_name,class FT>
typename Alpha_shape_3::Classification_type py_classify(const Alpha_shape_3& as,const class_name& cl, const double& alpha)
{
	return as.classify(cl,FT(alpha));
}


template <class kernel>
void Py_Alpha_shape_3()
{
	typedef CGAL::Alpha_shape_vertex_base_3<kernel>         Avb;
	typedef CGAL::Triangulation_vertex_base_with_info_3<boost::python::object,kernel,Avb> 	Vb;

	typedef CGAL::Alpha_shape_cell_base_3<kernel>           Fb;
	typedef CGAL::Triangulation_data_structure_3<Vb,Fb> 	Tds;
	typedef CGAL::Delaunay_triangulation_3<kernel,Tds>      Delaunay_triangulation_3;
	typedef CGAL::Alpha_shape_3<Delaunay_triangulation_3>   Alpha_shape_3;
	

	typedef typename Alpha_shape_3::Classification_type 	Classification_type;
	typedef typename Alpha_shape_3::Mode 					Mode;
	typedef typename Alpha_shape_3::Cell_handle 			Cell_handle;
	typedef typename Alpha_shape_3::Vertex_handle 			Vertex_handle;
	typedef typename Alpha_shape_3::Alpha_iterator 			Alpha_iterator;

	typedef typename Alpha_shape_3::Facet 		Facet;
	typedef typename Alpha_shape_3::Edge 		Edge;
	typedef CGAL::Point_3<kernel> 				Point_3;
	typedef typename kernel::FT					FT;
	typedef typename std::list<Cell_handle>::iterator  		OutputItCells;
	typedef typename std::list<Facet>::iterator  			OutputItFacets;
	typedef typename std::list<Edge>::iterator  			OutputItEdges;
	typedef typename std::list<Vertex_handle>::iterator  	OutputItVertices;


    scope* Alpha_shape_3_scope = new scope(
    class_< Alpha_shape_3, bases< Delaunay_triangulation_3 > , boost::noncopyable >("Alpha_shape_3",Alpha_shape_3_doc, init< optional< double, Mode > >())
        .def(init< Delaunay_triangulation_3&, optional< double, Mode > >())
        .def("make_alpha_shape", &py_make_alpha_shape<kernel,Alpha_shape_3>,make_alpha_shape_doc)
        .def("clear", &Alpha_shape_3::clear,clear_doc)
        .def("set_alpha", &Alpha_shape_3::set_alpha,set_alpha_doc)
        .def("set_alpha", &py_set_alpha<Alpha_shape_3>)

        .def("get_alpha", &Alpha_shape_3::get_alpha, return_value_policy< copy_const_reference >(),get_alpha_doc)
        .def("get_nth_alpha", &Alpha_shape_3::get_nth_alpha, return_value_policy< copy_const_reference >(),get_nth_alpha_doc)
        .def("number_of_alphas", &Alpha_shape_3::number_of_alphas,number_of_alphas_doc)
        .def("set_mode", &Alpha_shape_3::set_mode, set_mode_overloads_0_1(set_mode_doc))
        .def("get_mode", &Alpha_shape_3::get_mode,get_mode_doc)
        .def("alpha_find", &py_alpha_find<kernel,Alpha_iterator,Alpha_shape_3>,alpha_find_doc)
        .def("alpha_lower_bound", &py_alpha_lower_bound<kernel,Alpha_iterator,Alpha_shape_3>,alpha_lower_bound_doc)
        .def("alpha_upper_bound", &py_alpha_upper_bound<kernel,Alpha_iterator,Alpha_shape_3>,alpha_upper_bound_doc)
        .def("classify", (Classification_type (Alpha_shape_3::*)(const Point_3&) const)&Alpha_shape_3::classify)

        .def("classify", &py_classify<Alpha_shape_3,Point_3,FT>,classify_doc)

        .def("classify", (Classification_type (Alpha_shape_3::*)(const Cell_handle&) const)&Alpha_shape_3::classify)

        .def("classify", &py_classify<Alpha_shape_3,Cell_handle,FT>)

        .def("classify", (Classification_type (Alpha_shape_3::*)(const Edge&) const)&Alpha_shape_3::classify)

        .def("classify", &py_classify<Alpha_shape_3,Edge,FT>)

        .def("classify", (Classification_type (Alpha_shape_3::*)(const Facet&) const)&Alpha_shape_3::classify)

        .def("classify", &py_classify<Alpha_shape_3,Facet,FT>)

        .def("classify", (Classification_type (Alpha_shape_3::*)(const Vertex_handle&) const)&Alpha_shape_3::classify)

        .def("classify", &py_classify<Alpha_shape_3,Vertex_handle,FT>)

        .def("number_of_solid_components", (int (Alpha_shape_3::*)() const)&Alpha_shape_3::number_of_solid_components)
        .def("number_of_solid_components", &py_number_of_solid_components<Alpha_shape_3>,number_of_solid_components_doc)
        .def("find_optimal_alpha", &py_find_optimal_alpha<Alpha_iterator,Alpha_shape_3>,find_optimal_alpha_doc)

		.def("get_alpha_shape_cells", &py_get_alpha_shape_cells<Alpha_shape_3,Cell_handle>,get_alpha_shape_cells_doc)
		.def("get_alpha_shape_cells", &py_get_alpha_shape_cells_alpha<Alpha_shape_3,Cell_handle>)

		.def("get_alpha_shape_facets", &py_get_alpha_shape_facets<Alpha_shape_3,Facet>,get_alpha_shape_facets_doc)
		.def("get_alpha_shape_facets", &py_get_alpha_shape_facets_alpha<Alpha_shape_3,Facet>)

		.def("get_alpha_shape_edges", &py_get_alpha_shape_edges<Alpha_shape_3,Edge>,get_alpha_shape_edges_doc)
		.def("get_alpha_shape_edges", &py_get_alpha_shape_edges_alpha<Alpha_shape_3,Edge>)

		.def("get_alpha_shape_vertices", &py_get_alpha_shape_vertices<Alpha_shape_3,Vertex_handle>,get_alpha_shape_vertices_doc)
		.def("get_alpha_shape_vertices", &py_get_alpha_shape_vertices_alpha<Alpha_shape_3,Vertex_handle>)

        //.def("show_alpha_shape_faces", &Alpha_shape_3::show_alpha_shape_faces)
        .def("print_maps", &Alpha_shape_3::print_maps)
        .def("print_alphas", &Alpha_shape_3::print_alphas)
        .def("print_alpha_status", &Alpha_shape_3::print_alpha_status)
		
 		.add_property("alpha",py_alpha<Alpha_iterator,Alpha_shape_3>)

   );

    enum_< Classification_type >("Classification_type")
        .value("INTERIOR", Alpha_shape_3::INTERIOR)
        .value("REGULAR", Alpha_shape_3::REGULAR)
        .value("EXTERIOR", Alpha_shape_3::EXTERIOR)
        .value("SINGULAR", Alpha_shape_3::SINGULAR)
    ;


    enum_< Mode >("Mode")
        .value("REGULARIZED", Alpha_shape_3::REGULARIZED)
        .value("GENERAL", Alpha_shape_3::GENERAL)
    ;

    delete Alpha_shape_3_scope;

	simple_python_iterator<OutputItCells>::declare("OutputItCells");
	simple_python_iterator<OutputItFacets>::declare("OutputItFacets");
	simple_python_iterator<OutputItEdges>::declare("OutputItEdges");
	simple_python_iterator<OutputItVertices>::declare("OutputItVertices");
	simple_python_iterator<Alpha_iterator>::declare("Alpha_iterator");

}

void export_Alpha_shape_3()
{
	Py_Alpha_shape_3<K>();
}
